const fs = require('fs')
const path = require('path')
const vm = require('vm')

function Module(id) {
    this.id = id
    this.exports = {}
    // console.log(111);
}
Module._resolveFilename = function (filename) {
    // 利用 Path 将 filename 转为绝对路径
    let absPath = path.resolve(__dirname, filename)
    // 判断当前路径内容是否存在
    if(fs.existsSync(absPath)) {
        return absPath
    } else {
        // 不存在，尝试对其进行文件后缀的补足 (例: .js .json)
        let suffix= Object.keys(Module._extensions)
        for(var i=0; i<suffix.length; i++) {
            let newPath = absPath + suffix[i]   // 补足后缀
            // 重新判断路径
            if(fs.existsSync(newPath)){
                return newPath
            }
        }
    }
    throw new Error(`${filename} is not exists`)
}
Module._extensions = {
    '.js'(module) {
        // 读取路径文件中的内容
        let content = fs.readFileSync(module.id, 'utf-8')
        // 包装
        content = Module.wrapper[0] + content + Module.wrapper[1]
        // console.log(content);
        // vm
        let compileFn = vm.runInThisContext(content)
        // console.log(compileFn);
        // 准备参数的值
        let exports = module.exports
        let dirname = path.dirname(module.id)
        let filename = module.id
        // 调用
        compileFn.call(exports, exports, myRequire, module, filename, dirname)
    },
    '.json'(module) {
        let content = JSON.parse( fs.readFileSync(module.id, 'utf-8') )
        module.exports = content
    }
}
Module.wrapper = [
    "(function (exports, require, module, __filename, __dirname) {",
    "})"
]
Module._cache = {}
Module.prototype.load = function() {
    // 获取文件类型 .js or .json
    let extname = path.extname(this.id)

    Module._extensions[extname](this)
}

function myRequire(filename) {
    // 1. 绝对路径
    let mPath = Module._resolveFilename(filename)
    // 2. 缓存优先
    let cacheModule = Module._cache[mPath]
    if(cacheModule) return cacheModule.exports
    // 3. 没有缓存，创建空对象加载目标模块 将绝对路径作为对象的id
    let module = new Module(mPath)
    // 4. 缓存已经加载过的模块
    Module._cache[mPath] = module
    // 5. 执行加载 （编译执行）
    module.load()

    // 6. 返回数据
    return module.exports
}

let obj = myRequire('./v')
// let obj2 = myRequire('./v')
// let obj3 = myRequire('./v')
console.log(obj.name + '的年龄是' + obj.age + '岁')